#include "detectiontab.h"
#include "ui_detectiontab.h"

DetectionTab::DetectionTab(QWidget *parent) :
    QWidget(parent),
    m_ui(new Ui::DetectionTab),pOpener(new ProjectOpener),
    imgL(new ImageLoader)
{
    m_ui->setupUi(this);
}

DetectionTab::~DetectionTab()
{
    delete m_ui;
    if(pOpener) delete pOpener;
}

void DetectionTab::changeEvent(QEvent *e)
{
    QWidget::changeEvent(e);
    switch (e->type()) {
    case QEvent::LanguageChange:
        m_ui->retranslateUi(this);
        break;
    default:
        break;
    }
}
/*
 *  Open a project file which contains location of image files as well 
 *	as information related to project: number of family, number of petri
 *	dishes, time when image was captured.
 *
 */
void DetectionTab::populate(const QString &fileName)
{
	// Have project opener to make connections to database
    if(pOpener) pOpener->addFile(fileName);
    else return;
	// Get number of seed families in the project
    QStringList families = pOpener->getFamily();
    // Get all image files from the projectOpener
    QVector<QString>  files = pOpener->getFiles();

    if(files.size() > 0)
    {
		// Add to image loader for displaying 
        imgL->addFiles(files);
		// Clear any left over family information
        m_ui->familyComboBox->clear();
        m_ui->familyComboBox->addItem("----------");
        m_ui->familyComboBox->addItems(families);
		// Connect number of families to pdn drop down box
        connect(m_ui->familyComboBox, SIGNAL(activated(QString)),
                this, SLOT(updatePDN(QString)));
		// Load project start time and information of project
        m_ui->start_label->setText(pOpener->getStartTime());
        m_ui->info_text->setText(pOpener->getProjInfo());
		// Reload to populate combo drop down box
        reload();
    }
    else
    {
        QMessageBox msgBox;
        msgBox.setText("No image files can be opened!");
        msgBox.exec();
    }
}

/*
 *	Based on selected family number, update pdn drop down box to 
 *	only show petri dish number belonging to the family
 *
 */
void DetectionTab::updatePDN(QString family)
{
    if(family != tr("----------") && family.length() > 0)
    {
		// With selected family information, get pdn's within the family
        QStringList pdnList = pOpener->getPDN(family);
        m_ui->pdnComboBox->clear();
        m_ui->pdnComboBox->addItem("----------");
        m_ui->pdnComboBox->addItems(pdnList);
        updateChild(pdnList, 1);
        connect(m_ui->pdnComboBox, SIGNAL(activated(QString)),
                this, SLOT(updateTime(QString)));
    }
}

/*
 *	With selected pdn plus family, update time combo drop down box
 *
 */
void DetectionTab::updateTime(QString pdn)
{
	// Get selected family number of family drop down box
    QString family = m_ui->familyComboBox->currentText();
	// In order to get associated time with family and pdn, check if both drop down combo box 
	// have been selected 
    if(family != tr("----------") && family.length() > 0 && pdn != tr("----------") && pdn.length() > 0)
    {
		// Based on selected family and pdn, get time slots 
        QStringList timeList = pOpener->getTime(family, pdn);

        m_ui->timeComboBox->clear();
        m_ui->timeComboBox->addItem("----------");
        m_ui->timeComboBox->addItems(timeList);

        connect(m_ui->timeComboBox, SIGNAL(activated(QString)), this, SLOT(updateByTime(QString)));
    }
}

void DetectionTab::updateByTime(QString time)
{
    if(time.length() > 0 && time != tr("----------"))
    {

    }
}

/*
 *	Calculate and display 2-D histogram for current displayed image
 *	This histogram is based on h-channel and v-channel
 */
void DetectionTab::drawHistogram()
{
	// Current displayed image file name
    curr = imgL->getCurrFile();
	// Read in the file
    Mat img = imread(curr.toStdString());
	// check if the image has been successfully loaded
    if(!img.data) return;

    Mat hsv, rgb, histImg;
	// Convert current image from BGR to HSV format
    cvtColor(img, hsv, CV_BGR2HSV);

    int width = m_ui->histLabel->width();
    int height = m_ui->histLabel->height();
    double maxVal = 0;
    int max_pos;
	// Number of bins for h-channel and v-channel
    int hbins=20, vbins=12;
    int histSize[] = {hbins, vbins};
	// Range of h-channel and v-channel
    float hranges[] = {0, 180};
    float vranges[] = {0, 255};
    const float* ranges[] = {hranges, vranges};

    MatND hist;
    // compute the histogram from 1-st and 3-rd channel
    int channels[] = {0, 2};

    calcHist(&hsv, 1, channels, Mat(), hist, 2, histSize, ranges, true, false);
	// Normalize histogram 
    normalize(hist, hist, 0, hbins*vbins*100, NORM_MINMAX, -1, Mat());
	// Get location of max value and position within the histogram
    minMaxLoc(hist, 0, &maxVal, 0, &max_pos);

    m_ui->maxLabel->setText(QString::number(maxVal));
    m_ui->maxlocLabel->setText(QString::number(max_pos));
	// Set zero to histImg 
    histImg = Mat::zeros(height, width, img.type());

    Mat hsv_c = Mat(1, 1, CV_8UC3);
    Mat rgb_c = Mat(1, 1, CV_8UC3);
	// Get IplImage header of corresponding mat 
    IplImage hsv_i = hsv_c;
    IplImage rgb_i = rgb_c;
	// For each bin within hbins
    for(int x=0; x<hbins; x++)
    {
		// For each bin within vbins
        for(int y=0; y<vbins; y++)
        {
            int ind = x*vbins + y;
			// Get current histogram value 
            float bin_val = hist.at<float>(x, y);
            int va = cvRound(bin_val*height/maxVal);
			// Set color value to HSV image
            cvSet2D(&hsv_i, 0, 0, cvScalar(x*180.f/hbins, y*255.f/vbins, 255, 0));
			// Convert HSV image to BGR
            cvtColor(hsv_c, rgb_c, CV_HSV2BGR);
			// Get BGR color value
            CvScalar color = cvGet2D(&rgb_i, 0, 0);
			// Draw a rectangle on the histogram image
            rectangle(histImg, Point(ind*4, height),
                      Point(ind*4+3, height-va),
                      color, -1);            
		}
    }
	// Convert histogram image to RGB format
    cvtColor(histImg, rgb, CV_BGR2RGB);
	// Get underlying image data and width between each byte
    uchar *data = rgb.data;
    int bytes = rgb.step;
	// Generate QImage from data 
    QImage qTemp = QImage(data, width, height, bytes, QImage::Format_RGB888);
    m_ui->histLabel->setPixmap(QPixmap::fromImage(qTemp, 0));
}

/*
 *	Save current result image to 'file' provided by user
 *
 */
bool DetectionTab::saveImage(const QString &file)
{
	// Get current result displayed on right side of image loader
    Mat img = imgL->getResultImage();
	// If result image is valid
    if(img.data)
    {
		// Write the file and return the result 
        return imwrite(file.toStdString(), img);
    }

    return false;
}

/*
 *	Filter images based on filter and type. This method try to update image 
 *	based on filters: family, pdn and time from 
 *
 */
void DetectionTab::updateChild(const QStringList& filter, int type)
{
    // When type==1, update icons based on pdn numbers
    // which all belong to single family/genotype
    if(type == 1)
    {
        imgL->updateIcons(filter);
    }
    else if(type == 2)
    {

    }
    reload();
}

/*	
 *	Get current image on the left side of image loader
 *
 */
QString DetectionTab::getCurrImg()
{    
    if(imgL) curr = imgL->getCurrFile();
    return curr;
}

void DetectionTab::showContent()
{
    if(imgL != 0)
        m_ui->mainGridLayout->addWidget(imgL, 0, 0);
}

/*
 *	Reload image loader 
 *
 */
void DetectionTab::reload()
{
    imgL->reload();
}

/*
 *	Get current displayed image files
 */
QVector<QString> DetectionTab::getFiles()
{
    return imgL->getFiles();
}

/*
 *	Check if a project is currently opened
 */
bool DetectionTab::isProjOpened()
{
	// If project opener has not been initialized
    if(pOpener == 0) return false;
    // Both a project has been opened and image files have
    // been successfully loaded
    if(pOpener->isProjOpened() && imgL->getLoadedSize() > 0)
        return true;

    return false;
}
